package edu.bu.cs511.p5;


/**
 * Helper class for making the scheduling hierarchy.  This follows the
 * factory pattern.  Use the methods of this class to return the Tasks
 * which constitute the scheduler hierarchy defined by the composite
 * design pattern.<p/>
 *
 * Many of the constituent methods are separate instead of having
 * completely generic methods and relying on polymorphism because I
 * want the type-checking afforded by this approach.  The process of
 * creating the hierarchy should be as easy as possible, and having
 * explicitely denoted types in these methods should make its
 * construction more explicit.<p/>
 *
 * Gabriel Parmer, 2/22/06: created
 */
public class SchedHierarchy {
    /**
     * Return an instance of the ThreadManager for the system.<p/> 
     *
     * @EFFECTS return a new ThreadManager (which is a singleton).
     */
    public static ThreadManager createThdManager() {
        return ThreadManager.getInstance(null);
    }

    /**
     * Create the root scheduler, return it.
     * <p/>
     * @REQUIRES tm is the ThreadManager of the system and s is the type of
     * scheduler you wish this root scheduler to use.
     * <p/>
     * @MODIFIES create the root scheduler and attach it to the ThreadManager.
     * <p/>
     * @EFFECTS return the new SchedTask that has been created for the
     * root scheduler.
     */
    public static SchedTask rootScheduler(ThreadManager tm, IScheduler s) {
        SchedTask st = new SchedTask(s, tm);
        tm.setRootScheduler(st);

        return st;
    }

    /**
     * Take an already created parent, and add a scheduler child to it.  Return
     * the child task.
     * <p/>
     * @REQUIRES parent is the SchedTask that is to be the parent of this
     * scheduler while child is the type of scheduler you wish this scheduler to
     * use.
     * <p/>
     * @MODIFIES create this scheduler and attach it to the parent scheduler.
     * <p/>
     * @EFFECTS return the new SchedTask that has been created for this
     * scheduler.
     */
    public static SchedTask addScheduler(SchedTask parent, IScheduler child) {
        return addScheduler(parent, child, "");
    }

    /**
     * Take an already created parent, and add a scheduler child to it.  Return
     * the child task.
     * <p/>
     * @REQUIRES parent is the SchedTask that is to be the parent of this
     * scheduler while child is the type of scheduler you wish this scheduler to
     * use.
     * <p/>
     * @MODIFIES create this scheduler and attach it to the parent scheduler.
     * <p/>
     * @EFFECTS return the new SchedTask that has been created for this
     * scheduler.
     */
    public static SchedTask addScheduler(SchedTask parent, IScheduler child, String flowType) {
        SchedTask st = new SchedTask(child, parent);
        if (flowType.equals("")) {
            if (!parent.getScheduler().addTask(st)) return null;
        } else {
            if (!parent.getScheduler().addTask(st, flowType)) return null;
        }

        return st;
    }

    /**
     * Add an opcode as a task in a parent scheduling context.  Return the
     * opcode's Task.
     * <p/>
     * @REQUIRES parent is the scheduler under which the child should be
     * placed and child is the IOpcode task which contains the opcode's work.
     * <p/>
     * @EFFECTS return a new OpcodeTask for the child scheduled by the
     * parent.
     */
    public static OpcodeTask addOpcode(SchedTask parent, IOpcode child) {
        return addOpcode(parent, child, "");
    }


    /**
     * Add an opcode as a task in a parent scheduling context.  Return the
     * opcode's Task.
     * <p/>
     * @REQUIRES parent is the scheduler under which the child should be
     * placed and child is the IOpcode task which contains the opcode's work.
     * The flowType is the specification to pass to the scheduler concerning
     * specific information on how the opcode is to be scheduled.
     * <p/>
     * @EFFECTS return a new OpcodeTask for the child scheduled by the
     * parent.
     */
    public static OpcodeTask addOpcode(SchedTask parent, IOpcode child, String flowType) {
        OpcodeTask ot = new OpcodeTask(child, parent);
        if (flowType.equals("")) {
            if (!parent.getScheduler().addTask(ot)) return null;
        } else {
            if (!parent.getScheduler().addTask(ot, flowType)) return null;
        }

        return ot;
    }
    
	/**
	 * MJO:
	 * Used to map FlowType strings into actual schedulers.
	 * 
	 * @param type - a string RoundRobin|Proportional|FixedPriority
	 * @param concurrency - the concurrency amount (a number)
	 * @return a Scheduler of type "type" with concurrency "args" | null if the
	 * 		scheduler type specified could not be found
	 * 
	 */
    public static IScheduler allocScheduler(String type, int Concurrency) 
    {
    	if(type.equals("RoundRobin"))
    		return new RRScheduler(Concurrency);
    	if(type.equals("Proportional"))
    		return new ProportionalScheduler(Concurrency);
    	if(type.equals("FixedPriority"))
    		return new FPScheduler(Concurrency);
    	else
    		return null;
    }

	/**
	 * MJO:
	 * Used to map FlowType strings into actual schedulers.
	 * 
	 * @param type - a string RoundRobin|Proportional|FixedPriority
	 * @return a Scheduler of type "type" with concurrency "args" | null if the
	 * 		scheduler type specified could not be found
	 * 
	 */
    public static IScheduler allocScheduler(String type) 
    {
    	if(type.equals("RoundRobin"))
    		return new RRScheduler();
    	if(type.equals("Proportional"))
    		return new ProportionalScheduler();
    	if(type.equals("FixedPriority"))
    		return new FPScheduler();
    	else
    		return null;   	
    }
    
}
